package com.eascs.spider.kuaixiao.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * HttpClient工具
 * @author hzp
 *
 */
public class NetUtil {
	private static Logger logger = LoggerFactory.getLogger(NetUtil.class);
	
	public static CloseableHttpClient initHttpClient(){
		BasicCookieStore cookieStore = new BasicCookieStore();
		return initHttpClient(cookieStore ,true);
	}
	
	public static CloseableHttpClient initHttpClient(CookieStore cookieStore){
		return initHttpClient(cookieStore ,false);
	}
	/**
	 * 
	 * 初始化httpClient
	 * 
	 * @param cookieStore	null则为默认
	 * @return CloseableHttpClient
	 */
	public static CloseableHttpClient initHttpClient(CookieStore cookieStore ,boolean isProxy){
        SSLConnectionSocketFactory sslsf = null;
//        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT)
        		//设置请求和传输超时时间
        		.setConnectTimeout(60000).setConnectionRequestTimeout(30000).setSocketTimeout(60000)
        		.build();
        try {
			SSLContext sslContext = new SSLContextBuilder()
                                .loadTrustMaterial(null, new TrustStrategy() {
                //信任所有证书
                public boolean isTrusted(X509Certificate[] chain,
                                String authType) throws CertificateException {
                    return true;
                }
                    }).build();
			//跳过证书Hostname验证
            sslsf = new SSLConnectionSocketFactory(sslContext,new String[]{"TLSv1"}, null,NoopHostnameVerifier.INSTANCE);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslsf)
                .build();
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
        
        
		HttpClientBuilder httpClientBuilder = HttpClients.custom()
				.setDefaultRequestConfig(globalConfig)
				.setDefaultCookieStore(cookieStore)
		        .setConnectionManager(poolingHttpClientConnectionManager)
		        .setSSLSocketFactory(sslsf);
		//判断是否需要代理，代理参数是否完整
		if (isProxy) {
	        //添加代理
			String proxyIp = "http-pro.abuyun.com";
			String proxyPort = "9010";
			String proxyUser = "H70B99V9Z752485P";
			String proxyPassword = "67CA67814D3A9E21";
			
			CredentialsProvider credsProvider = new BasicCredentialsProvider();
			credsProvider.setCredentials(new AuthScope(proxyIp, Integer.valueOf(proxyPort)), new UsernamePasswordCredentials(proxyUser, proxyPassword));
			
			//配置代理
	        HttpHost proxy = new HttpHost(proxyIp, Integer.valueOf(proxyPort),"http");
			httpClientBuilder.setProxy(proxy);
			httpClientBuilder.setDefaultCredentialsProvider(credsProvider);
		}
		//生成httpClient
		CloseableHttpClient client = httpClientBuilder.build();
		
		return client;
	}
	
	/**
	 * post重连
	 * @param client
	 * @param httpPost
     * @return
     */
	public static CloseableHttpResponse execute(CloseableHttpClient client, HttpPost httpPost) {
		
		CloseableHttpResponse response = null;
		int i = 5;
		while (i>0) {
			try {
				response = client.execute(httpPost);
				i = 0;
			} catch (IOException e) {
				i--;
			}
		}
		return response;
	}
	/**
	 * get重连
	 * @param client
	 * @param httpGet
	 * @return
	 */
	public static CloseableHttpResponse execute(CloseableHttpClient client, HttpGet httpGet) {
		CloseableHttpResponse response = null;
		int i = 5;
		while (i>0) {
			try {
				response = client.execute(httpGet);
				i = 0;
			} catch (IOException e) {
				i--;
			}
		}
		return response;
	}
	
	
	/**
	 * 
	 * 初始化get请求
	 * 
	 * @param url 请求链接
	 * @param headers 请求头，默认为null
	 * @param params 请求参数，默认为null
	 * @return HttpGet
	 */
	public static HttpGet initHttpGet(String url, Map<String,String> headers, Map<String,String> params) {
		
		//封装请求参数
    	if(params!=null && !params.isEmpty()){
    		url = url + "?";
    		for(String key:params.keySet()){
    			url = url + key + "=" + params.get(key) + "&";
    		}
    		url = url.substring(0, url.length()-1);
    	}
		
		HttpGet httpGet = new HttpGet(url);
		
		//设置默认请求头
		httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded");
		httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
		
		//封装请求头
		if(headers!=null && !headers.isEmpty()){
			for(String key:headers.keySet()){
				httpGet.setHeader(key, headers.get(key));
			}
		}
		
		return httpGet;
	}
	/**
	 * 
	 * 初始化post请求
	 * 
	 * @param url 请求链接
	 * @param headers 请求头，默认为null
	 * @param params  请求参数，默认为null
	 * @param charset 请求参数编码方式，默认为UTF-8
	 * @return HttpPost
	 */
	public static HttpPost initHttpPost(String url, Map<String,String> headers, Map<String,String> params, String charset) {
		HttpPost httpPost = new HttpPost(url);
		
		//设置默认请求头
		httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
		httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
		
		//封装请求头
		if(headers!=null && !headers.isEmpty()){
			for(String key:headers.keySet()){
				httpPost.setHeader(key, headers.get(key));
			}
		}
		
		if(StringUtil.isNullOrEmpty(charset)){
			//指定编码“UTF-8”，防止参数中包含中文导致验证失败
			charset = "UTF-8";
		}
		
		//封装请求参数
		if(params!=null && !params.isEmpty()){
			try {
				httpPost.setEntity(new UrlEncodedFormEntity(packagePostParams(params),charset));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}	
		}
		
		return httpPost;
	}
	
	/**
	 * 
	 *  初始化post请求
	 * 
	 * @param url 请求链接
	 * @param entity jquery数据
	 * @return
	 */
	public static HttpPost initHttpPost(String url, HttpEntity entity) {
    	HttpPost httpPost = new HttpPost(url);
		
    	//设置默认请求头
		httpPost.setHeader("Content-Type", "application/json");
		httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
		httpPost.setHeader("ajaxRequest","true");
		httpPost.setHeader("X-Requested-With","XMLHttpRequest");
    	//设置提交参数
		httpPost.setEntity(entity);
		return httpPost;
	}
	/**
	 * 封装post参数
	 * @param postParams
	 * @return
	 */
	public static List<NameValuePair> packagePostParams(Map<String,String> postParams){
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		if(postParams!=null){
			for(String key:postParams.keySet()){
				nvps.add(new BasicNameValuePair(key, postParams.get(key)));
			}
		}
		return nvps;
	}
	
	/**
	 * 
	 * @param response
	 * @return
	 */
	public static String extractPageRawText(CloseableHttpResponse response){
		
		String pageRawText = null;
		try {
			pageRawText=EntityUtils.toString(response.getEntity(),"UTF-8");
		} catch (ParseException | IOException e) {
			e.printStackTrace();
		} catch (NullPointerException e){
			return null;
		} finally{
			try {
				response.close();
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}
		return pageRawText;
	}
 
    /**
     * 用不带参数的get方法获取网页内容
     * @param url
     * @param client
     * @return
     */
    public static String loadPageRawTextByGet(String url,CloseableHttpClient client){
    	return loadPageRawTextByGet(url,client,null);
    }
    /**
     * 用带参数的get方法获取网页内容
     * @param url
     * @param client
     * @param params
     * @return
     */
    public static String loadPageRawTextByGet(String url,CloseableHttpClient client, Map<String,String> params){
    	String RawText = null;
    	HttpGet httpGet = initHttpGet(url, null, params);
    	CloseableHttpResponse response = execute(client, httpGet);
		RawText = extractPageRawText(response);
		try {
			if(response!=null)
				response.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	return RawText;
    }
   
    public static String loadPageRawTextByGet(String url,CloseableHttpClient client, Map<String,String> header ,Map<String,String> params){
    	String RawText = null;
		try {
			HttpGet httpGet = initHttpGet(url, header, params);
	    	CloseableHttpResponse response = execute(client, httpGet);
			RawText = extractPageRawText(response);
			if(response!=null)
				response.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return RawText;
    }
    
    /**
     * 用post方法获取网页内容
     * @param url	post链接
     * @param client	httpclient
     * @param postParams	post参数
     * @return
     */
    public static String loadPageRawTextByPost(String url,CloseableHttpClient client, Map<String,String> postParams){
    	return loadPageRawTextByPost(url,client,postParams,"UTF-8");
    }
    
    /**
     * 用post方法获取网页内容
     * @param url	post链接
     * @param client	httpclient
     * @param postParams	post参数
     * @param charset	post参数编码字符集
     * @return
     */
    public static String loadPageRawTextByPost(String url,CloseableHttpClient client, Map<String,String> postParams, String charset){
    	String RawText = null;
    	HttpPost httpPost = initHttpPost(url, null, postParams, charset);
    	CloseableHttpResponse response = execute(client, httpPost);
		RawText = extractPageRawText(response);
		try {
			response.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return RawText;
    }
	
    /**
     * 用post方法获取网页内容
     * @param url	post链接
     * @param client	httpclient
     * @param postParams	post参数
     * @param charset	post参数编码字符集
     * @return
     */
    public static String loadPageRawTextByPost(String url,CloseableHttpClient client, Map<String, String> header,Map<String,String> postParams, String charset){
    	String RawText = null;
    	HttpPost httpPost = initHttpPost(url, header, postParams, charset);
    	
    	CloseableHttpResponse response = execute(client, httpPost);
    	RawText = extractPageRawText(response);
		try {
			response.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return RawText;
    }
    
    /**
     * 处理302重定向
     * @param response
     * @param queryId
     * @return
     */
    public static String load302Page(CloseableHttpResponse response, CloseableHttpClient client){
    	
    	while(response.getStatusLine().getStatusCode()==302){
    		String locationUrl=response.getLastHeader("Location").getValue();
    		HttpGet httpGet = initHttpGet(locationUrl, null, null);
    		response = execute(client, httpGet);
    	}
		
		return extractPageRawText(response);
    }
    
    /**
     * 刷新代理ip
     * @param client 当前使用的httpClient
     * @return
     */
    public static boolean reflushProxyIP(CloseableHttpClient client){
    	HttpGet httpGet = new HttpGet("http://http-pro.abuyun.com/current-ip");
    	httpGet.setHeader("Proxy-Switch-Ip", "yes");
    	try {
    		String proxy = extractPageRawText(client.execute(httpGet));
    		logger.info("阿布云代理刷新结果:{}" , proxy);
    		return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
    }
    
    /**
     * 刷新httpclient
     * @param client
     * @return
     */
    public static CloseableHttpClient reflushClient(CloseableHttpClient client){
    	try {
    		client.close();
    		client = null;
		} catch (IOException e) {
			// TODO: handle exception
		}
		CookieStore cookieStore = new BasicCookieStore();
		CloseableHttpClient clientNew = initHttpClient(cookieStore);
		NetUtil.reflushProxyIP(clientNew);
    	
    	return clientNew;
    }
    public static void main(String[] args) {
    	CookieStore cookieStore = new BasicCookieStore();
		CloseableHttpClient client = NetUtil.initHttpClient(cookieStore);
		NetUtil.reflushProxyIP(client);
		String html = NetUtil.loadPageRawTextByGet("http://blog.csdn.net/yu12377/article/details/73324364", client);
		System.out.println(html);
	}
}
